import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Serv {
	private ServerSocket servSock;
	private BlockingQueue<SocketRun> socketQueue = new LinkedBlockingQueue<SocketRun>();
	private boolean isWork;
	private static int count;

	public Serv(int port) throws IOException {
		servSock = new ServerSocket(port);
		System.out.println("Server is start");
		isWork = true;
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				BufferedReader br = new BufferedReader(new InputStreamReader(
						System.in));
				while (isWork) {
					try {
						String mess = br.readLine();
						if (mess.equals("shutdown")) {
							System.out.println("Server shuts down");
							for (SocketRun sr : socketQueue) {
								sr.close();
							}
							isWork = false;
						}
					} catch (IOException e) {
					} finally {
						try {
							br.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
				System.exit(0);
			}
		});
		t.start();
	}

	void waiter() {
		while (isWork) {
			Socket s = null;
			try {
				s = servSock.accept();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (s != null) {
				SocketRun socket;
				try {
					socket = new SocketRun(s);
					socketQueue.offer(socket);
					System.out.println("One new connection");
					count++;
					Thread thread = new Thread(socket);
					thread.start();
				} catch (IOException e) {
				}
			}
		}
	}

	private class SocketRun implements Runnable {

		Socket s;
		String name="User "+count;
		DataInputStream sockIn;
		DataOutputStream sockOut;

		public SocketRun(Socket s) throws IOException {
			this.s = s;
			sockIn = new DataInputStream(s.getInputStream());
			sockOut = new DataOutputStream(s.getOutputStream());
		}

		@Override
		public void run() {
			this.send("Server: Welcome! You are connected.");
			while (!s.isClosed()) {
				String line = null;
				try {
					line = sockIn.readUTF();

				} catch (IOException e) {
					close();
				}

				if (line == null) {
					close();
				} else {
					for (SocketRun sr : socketQueue) {
						sr.send(name+": "+line);
					}
				}
			}
		}

		private synchronized void send(String line) {
			try {
				sockOut.writeUTF(line);
				sockOut.flush();
			} catch (IOException e) {
				close();
			}

		}

		private synchronized void close() {
			try {
				sockOut.writeUTF("Server: You was disconected.");
				sockOut.flush();
			} catch (IOException e1) {
			}
			socketQueue.remove(this);
			if (!s.isClosed()) {
				try {
					s.close();
					System.out.println("One connection was close");
				} catch (IOException e) {
				}
			}

		}

	}

	public static void main(String[] args) throws IOException {
		count=0;
		new Serv(4592).waiter();
	}

}
